﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using matrixdotnet.Common;

namespace matrixdotnet.CommonDAL
{
    public class LazyDataEntity<TIdentity, TUniqueKey, TBusinessEntity, TDataEntity> :
        IDataEntity<TIdentity, TUniqueKey, TBusinessEntity>
        where TIdentity : struct
        where TUniqueKey : struct
        where TBusinessEntity : class, IBusinessEntity<TUniqueKey>
        where TDataEntity : class, IDataEntity<TIdentity, TUniqueKey, TBusinessEntity>, TBusinessEntity
    {
        private TIdentity _identity;
        private TDataEntity _dataEntity = null;
        protected IDataEntityFinder<TIdentity, TUniqueKey, TBusinessEntity, TDataEntity> Finder { get; set; }

        public LazyDataEntity(
            TIdentity identity,
            IDataEntityFinder<TIdentity, TUniqueKey, TBusinessEntity, TDataEntity> finder)
        {
            _identity = identity;
            Finder = finder;
        }

        public TIdentity? Identity
        {
            get { return _identity; }
            set { throw new ApplicationException("Invalid context of invocation"); }
        }

        public TUniqueKey UniqueKey
        {
            get { return DataEntity.UniqueKey; }
        }

        public TBusinessEntity BusinessEntity
        {
            get { return DataEntity.BusinessEntity; }
        }

        public long Version
        {
            get { return DataEntity.Version; }
            set { DataEntity.Version = value; }
        }

        public TIdentity Insert()
        {
            throw new ApplicationException("The data entity is not new and can't be inserted!");
        }

        public event EventHandler<DataEntityDirtyEventArgs> Dirty
        {
            add
            {
                if (NoEntity)
                    throw new ApplicationException("Bad context for invocation");

                _dataEntity.Dirty += value;
            }
            remove
            {
                if (NoEntity)
                    throw new ApplicationException("Bad context for invocation");

                _dataEntity.Dirty -= value;
            }
        }

        public event EventHandler<DataEntityConstraintIntegrityEventArgs> ConstraintIntegrity
        {
            add
            {
                if (NoEntity)
                    throw new ApplicationException("Bad context for invocation");

                _dataEntity.ConstraintIntegrity += value;
            }
            remove
            {
                if (NoEntity)
                    throw new ApplicationException("Bad context for invocation");

                _dataEntity.ConstraintIntegrity -= value;
            }
        }

        public bool IsNew
        {
            get { return false; }
        }

        public bool IsDirty
        {
            get
            {
                return NoEntity ? false : _dataEntity.IsDirty;
            }
        }

        public DataEntityState EntityState
        {
            get
            {
                if (NoEntity)
                    return DataEntityState.Unchanged;

                return _dataEntity.IsDirty ? DataEntityState.Modified : DataEntityState.Unchanged;
            }
        }

        public int Update()
        {
            if (NoEntity)
                throw new ApplicationException("Bad context for invocation");

            return _dataEntity.Update();
        }

        public void Create()
        {
            Insert();
        }

        public int Delete()
        {
            return DataEntity.Delete();
        }

        protected bool NoEntity
        {
            get { return _dataEntity == null; }
        }

        protected TDataEntity DataEntity
        {
            get
            {
                if (_dataEntity != null)
                    _dataEntity = Finder.FindDataEntity(Identity.Value);

                return _dataEntity;
            }
        }
    }
}
